#include <iostream>
#include <QtGui>
#include <QRect>
#include <QMenu>

#include "scribblearea.h"
//#include "db.h" we got conflicts here because of prevous ones..
#include "ui/use_add_dialog.h"

using namespace std;

 ScribbleArea::ScribbleArea(QWidget *parent)
     : QWidget(parent)
 {
     setAttribute(Qt::WA_StaticContents);
     modified = false;
     scribbling = false;
     myPenWidth = 2;
     myPenColor = Qt::black;
     menuRectIndex = -1; // some initial 
     validZoneMenu = false;
     
     //create the action list
     createActions();
     
     //load the default image
     fileOperation(0);

   
 }

//boiler code nothing important
bool ScribbleArea::fileOperation(int reverse=0){
 
     QString f_temp=QDir::currentPath();
     DbOperation *db = new DbOperation();
    
     //i hate that feature FIXME dont like it
     char *stupid_str=new char[f_temp.size()+1];
     strcpy(stupid_str,f_temp.toStdString().c_str());

     if(reverse==0)
        db->moveFile(
             stupid_str,
             stupid_str,
             "shot.png",
             "shot_copy.png",
             0
             );
     else
         db->moveFile(
             stupid_str,
             stupid_str,
             "shot_copy.png",
             "shot.png",
             0
             );
    
     delete db;
     db=0;
     delete []stupid_str;
     stupid_str=0;

     f_temp += QString("/shot.png");
     openImage(f_temp);
    
   
    return true;
}


 /**
  * That method will load the rigth click menu into system
  */

void ScribbleArea::createActions(){
 
    getPropertiesAct=new QAction(tr("&Properties"), this);
    connect(getPropertiesAct, SIGNAL(triggered()), this, SLOT(getProperties()));

    addPolicyAct=new QAction(tr("&Add Policy"), this);
    connect(addPolicyAct, SIGNAL(triggered()), this, SLOT(addPolicyGui()));
    
    editPolicyAct=new QAction(tr("&Edit Policy"), this);
    connect(editPolicyAct, SIGNAL(triggered()), this, SLOT(editPolicy()));
    
    removeZoneAct=new QAction(tr("&Remove Zone"), this);
    connect(removeZoneAct, SIGNAL(triggered()), this, SLOT(removeZone()));

    resetZoneAct=new QAction(tr("&Reset Zone"), this);
    connect(resetZoneAct, SIGNAL(triggered()), this, SLOT(resetZone()));
 }

    
void ScribbleArea::getProperties(){
    cout << "Get Properties called with id :"<< menuRectIndex << endl;
    //bool res;
    //qrectemp=rectList.at(menuRectIndex);
    //res =qrectemp.listPolicy();
    //if(res){
    //    rectList.removeAt(menuRectIndex);
    //    rectList.append(qrectemp);
    //}

  // the main widget 

  qrectemp=rectList.at(menuRectIndex);
  QList<Zone> tempqlist;
  tempqlist.append(qrectemp);
  
  QTreeWidget *tree_zoner=new QTreeWidget(0);
  produceZoneTree(tempqlist,tree_zoner);
  tree_zoner->show();
 
 }

/**
 * Method is needed because it produces a tree 
 * for current passed zones to it
 * needed in xml generation and properties windowww
 *
 * @param temp_rectList : a list with zone objects
 *
 * return QTreeWidgetItem object
 * 
 */

void ScribbleArea::produceZoneTree(const QList<Zone> &temp_rectList,QTreeWidget *mw){
   
  mw->setColumnCount(5);
  mw->setEditTriggers(QAbstractItemView::AllEditTriggers);
  
  QList<QTreeWidgetItem*> tree_zone_list;
 
  for(int i=0;i<temp_rectList.size();i++){
      
      QTreeWidgetItem *qw = new QTreeWidgetItem();
      
      //add the coordinates child
     
      int x1,x2,y1,y2;

     temp_rectList.at(i).getCoords(&x1,&y1,&x2,&y2);

      QTreeWidgetItem *qw_coord = new QTreeWidgetItem();
      qw_coord->setText(0,"coord");
      qw_coord->setText(1,QString("%2").arg(x1));
      qw_coord->setText(2,QString("%2").arg(y1));
      qw_coord->setText(3,QString("%2").arg(x2));
      qw_coord->setText(4,QString("%2").arg(y2));

      //add the policy children
      qw->addChild(qw_coord);
      
      for(int j=0;j<temp_rectList.at(i).policy_list.size();j++){
          QTreeWidgetItem *qw_policy = new QTreeWidgetItem();
          qw_policy->setText(0,"policy");
          qw_policy->setText(1,temp_rectList.at(i).policy_list.at(j).policy_name);
          qw->addChild(qw_policy);

          int p_num = temp_rectList.at(i).policy_list.at(j).person_list.size();
          for(int k=0;k<p_num;k++){
            QTreeWidgetItem *qw_person = new QTreeWidgetItem();
            qw_person->setText(0,temp_rectList.at(i).policy_list.at(j).person_list.at(k));
            qw_policy->addChild(qw_person);
          }
      }
      
      tree_zone_list.append(qw);
      QString t_s("zone");
      t_s.append(QString("%1").arg(i));
      //cout << "The zone name is hey : "<<t_s.toStdString()<<endl;
      
      tree_zone_list.at(i)->setText(0,t_s);
      tree_zone_list.at(i)->setFlags(Qt::ItemIsEnabled);
    
  
  }
  mw->insertTopLevelItems(0,tree_zone_list);
  //return mw;
}

 void ScribbleArea::addPolicyGui(){
 
    cout << "addPolicy called with id :"<< menuRectIndex << endl;
    //the dialog stuff here
    UiAddPol ua;
    int result;
    result=ua.exec();


    if(result==0){
        std::cout << "Nothing will happen sorry"<<std::endl;

    }
    else{
        //get the selected policy
        QString t_policy=ua.comboPolicy->currentText();
        std::cout << "Chosen policy is : "<<t_policy.toStdString()<<std::endl;


        //get the selected person list
        QItemSelectionModel *qm = ua.treePersonList->selectionModel();
        QList<QModelIndex> qli = qm->selectedRows();
        QList<QString> t_personlist;

        //make ready them for addition
        for(int i=0;i<qli.size();i++){
            std::cout << "Chosen person  is : "<<qli.at(i).data().toString().toStdString()<<std::endl;
            t_personlist.append(qli.at(i).data().toString());
        }

        //do the action here
        bool resultb=false;

        qrectemp=rectList.at(menuRectIndex);
        resultb=qrectemp.addPolicy(t_policy,t_personlist);
        if(resultb){
            rectList.removeAt(menuRectIndex);
            rectList.append(qrectemp);
        }   
 
    }

 }//end of the function

 void ScribbleArea::editPolicy(){
 
    cout << "Edit Policy called with id :"<< menuRectIndex << endl;
 }

 void ScribbleArea::removeZone(){
   
    //firstly clear the image then draw all the ones except 
    //the one you removed from the list
    rectList.removeAt(menuRectIndex);
    validRemoveZone=true; //little bit hacky 
    clearImage();
    cout << "debug debıg debug" << endl;

    //set a painter
    QPainter painter(&image);
    painter.setPen(QPen(myPenColor, myPenWidth, Qt::SolidLine, Qt::RoundCap,
                         Qt::RoundJoin));

     for(int i=0;i<rectList.size();i++){
        cout << "Im drawimg back the member : "<<i <<endl;
        painter.drawRect(rectList.at(i));
        //modified = true;
        int rad = (myPenWidth / 2) + 2;
        update(rectList.at(i).normalized().adjusted(-rad, -rad, +rad, +rad));
         
    }
    cout << "Remove Zone called with id :"<< menuRectIndex << endl;
    validRemoveZone=false; //turn it off again
 }

 void ScribbleArea::resetZone(){
  
    //work around to pass the 
    qrectemp=rectList.at(menuRectIndex);
    bool  result=qrectemp.resetIt();
    if(result){
        rectList.removeAt(menuRectIndex);
        rectList.append(qrectemp);
    }
    cout << "Reset zone called with id :"<< menuRectIndex << "and the result is :"<< result<<endl;
 }

 void ScribbleArea:: contextMenuEvent(QContextMenuEvent *event){
    
    //make it visible only for zone not in other places
    if(validZoneMenu){
    QMenu zoneMenu(this);
    zoneMenu.addAction(getPropertiesAct);
    zoneMenu.addAction(addPolicyAct);
    zoneMenu.addAction(editPolicyAct);
    zoneMenu.addAction(removeZoneAct);
    zoneMenu.addAction(resetZoneAct);
    zoneMenu.exec(event->globalPos());
    }
 }

 bool ScribbleArea::openImage(const QString &fileName)
 {
     QImage loadedImage;
     if (!loadedImage.load(fileName)){
         std::cout << "It wasnt load sorry" << std::endl;
         return false;
     }

     QSize newSize = loadedImage.size().expandedTo(size());
     resizeImage(&loadedImage, newSize);
     image = loadedImage;
     modified = false;
     update();
     return true;
 }

 bool ScribbleArea::saveImage(const QString &fileName, const char *fileFormat)
 {
     QImage visibleImage = image;
     resizeImage(&visibleImage, size());

     if (visibleImage.save(fileName, fileFormat)) {
         modified = false;
         return true;
     } else {
         return false;
     }
 }

 void ScribbleArea::setPenColor(const QColor &newColor)
 {
     myPenColor = newColor;
 }

 void ScribbleArea::setPenWidth(int newWidth)
 {
     myPenWidth = newWidth;
 }

 void ScribbleArea::clearImage()
 {
     //image.fill(qRgb(255, 255, 255));
     fileOperation(1);
     modified = true;

     //if clear the image should also clear the rectangles
     if(rectList.size()!=0 & !validRemoveZone)
         rectList.clear();

     update();
 }

 void ScribbleArea::mousePressEvent(QMouseEvent *event)
 {
     if (event->button() == Qt::LeftButton) {
         lastPoint = event->pos();
         scribbling = true;
     }
     //if we click to do some other stuff here
     else if(event->button()==Qt::RightButton){
        rigthClickPoint = event->pos();
        bool found = false;
        for(int i=0;i<rectList.size();i++){
            
            if(rectList.at(i).contains(rigthClickPoint)){
                //cout << "The point is inside the rect the menu will appear" << endl;
                found = true;
                validZoneMenu = true;
                menuRectIndex = i;

                break;
            }
             }

        //if we are not  in a zone than make them invalid
        if(!found){
            validZoneMenu = false;
            menuRectIndex = -1;
         }
        

     }
 }

/**
 void ScribbleArea::mouseMoveEvent(QMouseEvent *event)
 {
     if ((event->buttons() & Qt::LeftButton) && scribbling)
         drawLineTo(event->pos());
 }
 */

 void ScribbleArea::mouseReleaseEvent(QMouseEvent *event)
 {
     if (event->button() == Qt::LeftButton && scribbling) {
         drawLineTo(event->pos());
         scribbling = false;
     }
 }

 void ScribbleArea::paintEvent(QPaintEvent * /* event */)
 {
     QPainter painter(this);
     painter.drawImage(QPoint(0, 0), image);
 }

 void ScribbleArea::resizeEvent(QResizeEvent *event)
 {
     if (width() > image.width() || height() > image.height()) {
         int newWidth = qMax(width() + 128, image.width());
         int newHeight = qMax(height() + 128, image.height());
         resizeImage(&image, QSize(newWidth, newHeight));
         update();
     }
     QWidget::resizeEvent(event);
 }

 void ScribbleArea::drawLineTo(const QPoint &endPoint)
 {
     QPainter painter(&image);
     painter.setPen(QPen(myPenColor, myPenWidth, Qt::SolidLine, Qt::RoundCap,
                         Qt::RoundJoin));
     
     //lets draw it
     qrectemp = Zone(lastPoint,endPoint);

     //we shoulf check if there are some intersection we dont want intersections :)
     int tem_list_size = rectList.size();
     //cout << "The size of the rectangle list is : " << tem_list_size << endl;

     bool intersect = false;

     for(int i=0;i<tem_list_size;i++){
      
    if(rectList.at(i).intersects(qrectemp)){
         cout << "Intersection occured sorry it wont be drawn" << endl;
            intersect = true;
            break;
             }
     }
    
     //it may be the first time yoo
     if (tem_list_size==0 || intersect==false){
         rectList.append(qrectemp);
       
         cout << "That one was added to db" << endl;
         painter.drawRect(qrectemp);
         modified = true;
         int rad = (myPenWidth / 2) + 2;
         update(Zone(lastPoint, endPoint).normalized()
                                      .adjusted(-rad, -rad, +rad, +rad));
         
         lastPoint = endPoint;
        }

   }

 void ScribbleArea::resizeImage(QImage *image, const QSize &newSize)
 {
     if (image->size() == newSize)
         return;

     QImage newImage(newSize, QImage::Format_RGB32);
     newImage.fill(qRgb(255, 255, 255));
     QPainter painter(&newImage);
     painter.drawImage(QPoint(0, 0), *image);
     *image = newImage;
 }

 void ScribbleArea::print()
 {
     QPrinter printer(QPrinter::HighResolution);

     QPrintDialog *printDialog = new QPrintDialog(&printer, this);
     if (printDialog->exec() == QDialog::Accepted) {
         QPainter painter(&printer);
         QRect rect = painter.viewport();
         QSize size = image.size();
         size.scale(rect.size(), Qt::KeepAspectRatio);
         painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
         painter.setWindow(image.rect());
         painter.drawImage(0, 0, image);
     }
 }
